/**
 * Copyright 2011 Joe Choi, All rights reserved.
 */
package tao.calendar.gregorian;

import tao.time.AbstractTime;

/**
 * The ConcreteGregorianTime class is an implementation of GregorianDateTime
 * 
 * @author Joe Choi
 * @version 1.0.0
 */
class ConcreteGregorianTime extends AbstractTime implements GregorianTime {
	public ConcreteGregorianTime(GregorianTime time) {
		this(time.scalar());
	}
	
	public ConcreteGregorianTime(long scalar) {
		construct(scalar);
	}
	
	public ConcreteGregorianTime(int hour, int minute, int second, int millis) {
		normalize(hour, minute, second, millis);
	}

	/**
	 * Get the scalar of this time
	 */	
	@Override
	public long scalar() {
		return(	(getHour() * GregorianTime.HOUR_MILLIS) + 
				(getMinute() * GregorianTime.MINUTE_MILLIS) + 
				(getSecond() * GregorianTime.SECOND_MILLIS) + 
				(getMillisecond()));
	}
	
	@Override
	public String toString() {
		return(hour + ":" + minute + ":" + second + "." + millisecond);
	}

	@Override
	public int getHour() {
		return(hour);
	}

	@Override
	public int getMinute() {
		return(minute);
	}

	@Override
	public int getSecond() {
		return(second);
	}

	@Override
	public int getMillisecond() {
		return(millisecond);
	}

	protected void setInternalHour(int hour) {
		if(hour < 0 || hour > 23) throw new IllegalArgumentException("Invalid value of hour: " + hour);
		this.hour = hour;
	}

	protected void setInternalMinute(int minute) {
		if(minute < 0 || minute > 59) throw new IllegalArgumentException("Invalid value of minute: " + minute);
		this.minute = minute;
	}

	protected void setInternalSecond(int second) {
		if(second < 0 || second > 59) throw new IllegalArgumentException("Invalid value of second: " + second);
		this.second = second;
	}

	protected void setInternalMillisecond(int ms) {
		if(ms < 0 || ms > 999) throw new IllegalArgumentException("Invalid value of millisecond: " + ms);
		this.millisecond = ms;
	}

	protected void construct(long scalar) {
		int hr, min, sec, ms;
		
		//scalar %= DAY_MILLIS;
		scalar = Normalizer.module(scalar, DAY_MILLIS);
		
		hr = (int) (scalar / GregorianTime.HOUR_MILLIS);
		scalar %= GregorianTime.HOUR_MILLIS;
		
		min = (int) (scalar / GregorianTime.MINUTE_MILLIS);
		scalar %= GregorianTime.MINUTE_MILLIS;
		
		sec = (int) (scalar / GregorianTime.SECOND_MILLIS);		
		ms = (int) (scalar % GregorianTime.SECOND_MILLIS);
		normalize(hr, min, sec, ms);
	}
	
	protected void normalize(int hour, int minute, int second, int millis) {
		setInternalHour(Normalizer.module(hour, 24)); 
		setInternalMinute(Normalizer.module(minute, 60));
		setInternalSecond(Normalizer.module(second, 60));
		setInternalMillisecond(Normalizer.module(millis, 1000));		
	}
	
	private int hour, minute, second, millisecond;
}